package com.starlink.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.starlink.common.utils.AssertUtil;
import com.starlink.context.SessionContext;
import com.starlink.model.domain.PointsAcquireBillDO;
import com.starlink.model.request.MallRefundPriceRequest;
import com.starlink.model.request.PointsAcquireBillRequest;
import com.starlink.model.util.CheckInRecordsConvert;
import com.starlink.model.vo.CheckInRecordsVO;
import com.starlink.model.vo.system.WechatCheckInAndPointVO;
import com.starlink.model.dtomapper.CheckInRecordsDtoMapper;
import com.starlink.model.domain.CheckInRecordsDO;
import com.starlink.mapper.CheckInRecordsMapper;
import com.starlink.model.request.CheckInRecordsRequest;
import com.starlink.service.CheckInRecordsService;
import com.starlink.service.MallRefundPriceService;
import com.starlink.service.PointsAcquireBillService;
import com.starlink.service.PointsService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

import static com.starlink.common.enums.AcquireModeEnum.*;
import static com.starlink.common.enums.ActionTypeEum.*;
import static com.starlink.common.enums.BooleanEnum.FALSE;
import static com.starlink.common.enums.BooleanEnum.TRUE;
import static com.starlink.utils.IDUtils.getId;

/**
 * @author zhanghong
 */
@Service
public class CheckInRecordsServiceImpl extends ServiceImpl<CheckInRecordsMapper, CheckInRecordsDO> implements CheckInRecordsService {
    @Autowired
    private CheckInRecordsMapper checkInRecordsMapper;
    @Autowired
    private PointsAcquireBillService acquireBillService;
    @Autowired
    private PointsService pointsService;


    @Override
    public WechatCheckInAndPointVO getInfo() {
        WechatCheckInAndPointVO checkInAndPointVO = new WechatCheckInAndPointVO();
        Long userId = SessionContext.getWechatUserId();
        // 获取当前日期时间
        LocalDate currentDate = LocalDate.now();
        // 计算当前日期所在周的周一日期时间
        LocalDate firstDayOfWeek = currentDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        List<CheckInRecordsDO> list = this.lambdaQuery()
                .eq(CheckInRecordsDO::getUserId, userId)
                .apply("DATE_FORMAT(create_time, '%Y-%m-%d') BETWEEN {0} AND {1}", firstDayOfWeek, currentDate)
                .list();
        if (CollectionUtils.isEmpty(list)){
            list = new ArrayList<>();
            checkInAndPointVO.setConsecutiveDays(FALSE.getCode());
        }else {
            Integer[] weekDays = list.stream().map(CheckInRecordsDO::getWeekDay).sorted().toArray(Integer[]::new);
            int maxConsecutive = lastConsecutiveLength(weekDays);//计算最大签到天数
            checkInAndPointVO.setConsecutiveDays(maxConsecutive);
            Date newDate = list.stream().map(CheckInRecordsDO::getCreateTime).sorted(Comparator.reverseOrder()).findFirst().orElse(null);
            if (newDate!=null){
                LocalDate date = newDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                boolean dateEqual = date.isEqual(currentDate);
                if (dateEqual){
                    checkInAndPointVO.setIsCheckedIn(TRUE.getCode());
                }else {
                    checkInAndPointVO.setIsCheckedIn(FALSE.getCode());
                }
            }else {
                checkInAndPointVO.setIsCheckedIn(FALSE.getCode());
            }
        }
        List<CheckInRecordsVO> recordsVOS = CheckInRecordsConvert.buildCheckInRecordsVoList(list);
        checkInAndPointVO.setCheckInRecordsVOList(recordsVOS);
        PointsAcquireBillDO one = acquireBillService.lambdaQuery()
                .eq(PointsAcquireBillDO::getUserId, userId)
                .eq(PointsAcquireBillDO::getAcquireMode, XIN_SHOU.getType())
                .eq(PointsAcquireBillDO::getTitle, PERFECT_PERSONAL_INFO.getType())
                .one();
        if (ObjectUtils.isEmpty(one)){
            checkInAndPointVO.setUserInfoTask(FALSE.getCode());
        }else {
            checkInAndPointVO.setUserInfoTask(TRUE.getCode());
        }
        PointsAcquireBillDO two = acquireBillService.lambdaQuery()
                .eq(PointsAcquireBillDO::getUserId, userId)
                .eq(PointsAcquireBillDO::getAcquireMode, XIN_SHOU.getType())
                .eq(PointsAcquireBillDO::getTitle, BIND_PHONE_NUMBER.getType())
                .one();
        if (ObjectUtils.isEmpty(two)){
            checkInAndPointVO.setBundPhoneTask(FALSE.getCode());
        }else {
            checkInAndPointVO.setBundPhoneTask(TRUE.getCode());
        }
        PointsAcquireBillDO three = acquireBillService.lambdaQuery()
                .eq(PointsAcquireBillDO::getUserId, userId)
                .eq(PointsAcquireBillDO::getAcquireMode, RI_CHANG.getType())
                .eq(PointsAcquireBillDO::getTitle, BROWSE_PAGE.getType())
                .apply("date(create_time) = {0}", currentDate)
                .one();
        if (ObjectUtils.isEmpty(three)){
            checkInAndPointVO.setLiuLanTask(FALSE.getCode());
        }else {
            checkInAndPointVO.setLiuLanTask(TRUE.getCode());
        }
        PointsAcquireBillDO four = acquireBillService.lambdaQuery()
                .eq(PointsAcquireBillDO::getUserId, userId)
                .eq(PointsAcquireBillDO::getAcquireMode, RI_CHANG.getType())
                .eq(PointsAcquireBillDO::getTitle, INVITE_FRIENDS_TO_REGISTER.getType())
                .apply("date(create_time) = {0}", currentDate)
                .one();
        if (ObjectUtils.isEmpty(four)){
            checkInAndPointVO.setZhuCeTask(FALSE.getCode());
        }else {
            checkInAndPointVO.setZhuCeTask(TRUE.getCode());
        }

        List<PointsAcquireBillDO> five = acquireBillService.lambdaQuery()
                .eq(PointsAcquireBillDO::getUserId, userId)
                .eq(PointsAcquireBillDO::getAcquireMode, CHUAN_BO.getType())
                .eq(PointsAcquireBillDO::getTitle, SHARE_CONTENT.getType())
                .apply("date(create_time) = {0}", currentDate)
                .list();
        if (CollectionUtils.isEmpty(five)){
            checkInAndPointVO.setFenXiangTask(0);
        }else if (five.size()==0){
            checkInAndPointVO.setFenXiangTask(0);
        } else if (five.size()==1){
            checkInAndPointVO.setFenXiangTask(1);
        }else if (five.size()==2){
            checkInAndPointVO.setFenXiangTask(2);
        }

        return checkInAndPointVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean signIn(CheckInRecordsRequest request) {
        CheckInRecordsDO checkInRecordsDO = CheckInRecordsDtoMapper.INSTANCE.request2DO(request);
        Long userId = checkInRecordsDO.getUserId();
        AssertUtil.assertNotNull(userId,"用户ID不能为空");
        // 获取当前日期
        LocalDate today = LocalDate.now();
        CheckInRecordsDO check = this.lambdaQuery()
                .eq(CheckInRecordsDO::getUserId, userId)
                .apply("date(create_time) = {0}", today)
                .one();
        AssertUtil.assertNull(check,"不可重复签到!");
        // 创建 Calendar 实例并获取当前日期
        Calendar calendar = Calendar.getInstance();
        // 获取当前是星期几，并将星期天的数字表示转换为7
        int dayOfWeek = (calendar.get(Calendar.DAY_OF_WEEK) + 5) % 7 + 1;
        checkInRecordsDO.setIsCheckedIn(TRUE.getCode());
        checkInRecordsDO.setWeekDay(dayOfWeek);
        CheckInRecordsDO recordsDO = this.lambdaQuery()
                .eq(CheckInRecordsDO::getUserId, userId)
                .orderByDesc(CheckInRecordsDO::getCreateTime)
                .last("LIMIT 1")
                .one();
        if (recordsDO!=null){
            Date createTime = recordsDO.getCreateTime();
            LocalDate localDate = createTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            Integer consecutiveDays = recordsDO.getConsecutiveDays();
            if (Math.abs(today.toEpochDay() - localDate.toEpochDay()) == 1){
                checkInRecordsDO.setConsecutiveDays(consecutiveDays+1);
            }else {
                checkInRecordsDO.setConsecutiveDays(TRUE.getCode());
            }
        }else {
            checkInRecordsDO.setConsecutiveDays(TRUE.getCode());
        }
        checkInRecordsDO.setCreateUser(userId);
        checkInRecordsDO.setId(getId());
        checkInRecordsMapper.insertDO(checkInRecordsDO);
        //添加签到积分
        PointsAcquireBillRequest acquireBillRequest = new PointsAcquireBillRequest();
        acquireBillRequest.setUserId(userId);
        acquireBillRequest.setTitle(CHECK_IN_AND_EARN_POINTS.getType());
        acquireBillRequest.setAcquireMode(RI_CHANG.getType());
        acquireBillRequest.setAcquirePoint(calculateB(checkInRecordsDO.getConsecutiveDays()));
        acquireBillRequest.setCreateUser(userId);
        acquireBillRequest.setCreateTime(new Date());
        pointsService.addPoint(acquireBillRequest);
        return true;
    }

    public static int calculateB(int a) {
        int cycleLength = 7;  // 周期长度
        int b = ((a - 1) % cycleLength) + 1;  // 计算b的值
        return b;
    }

    /**
     * 计算连续签到天数
     * @param nums
     * @return
     */
    public static int lastConsecutiveLength(Integer[] nums) {
        int length = 1; // 初始长度为1，因为至少有一个数字
        int n = nums.length;

        // 从倒数第二个数字开始向前遍历
        for (int i = n - 2; i >= 0; i--) {
            // 如果当前数字比前一个数字大1，说明是连续的
            if (nums[i] == nums[i + 1] - 1) {
                length++;
            } else {
                // 如果不连续，直接返回当前长度
                break;
            }
        }
        return length;
    }
}
